from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from django.contrib.auth import authenticate, login
from .serializers import UserRegisterSerializer, AdminRegisterSerializer, LoginSerializer
from django.http import HttpResponse
import logging
logger = logging.getLogger(__name__)


# 第二次调试，新增了使用print函数讲注册时的信息直接输出到控制台，方便调试
class UserRegisterAPIView(APIView):
    def post(self, request):

        serializer = UserRegisterSerializer(data=request.data)
        print("Data received: ", request.data)  # 打印接收到的注册信息
        if serializer.is_valid():

            serializer.save()
            
            print("User registered successfully")  # 打印用户注册成功的信息
            return Response({'code': 1, "message": "User registered successfully"}, status=status.HTTP_201_CREATED)
        print(f"Registration failed: {serializer.errors}")  # 打印注册失败的错误信息
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class AdminRegisterAPIView(APIView):
    def post(self, request):
        print("Received admin registration request")  # 打印接收到管理员注册请求的信息
        serializer = AdminRegisterSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            print("Admin registered successfully")  # 打印管理员注册成功的信息
            return Response({'code': 1, "message": "Admin registered successfully"}, status=status.HTTP_201_CREATED)
        print(f"Admin registration failed: {serializer.errors}")  # 打印管理员注册失败的错误信息
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


# 登陆时保存用户信息到session
# 第一次调试

class LoginAPIView(APIView):
    def post(self, request):
        serializer = LoginSerializer(data=request.data)
        if serializer.is_valid():
            username = serializer.data.get('username')
            password = serializer.data.get('password')
            user = authenticate(request, username=username, password=password)
        print(f"User found: {user}")  # 打印找到的用户信息
        if user is not None:
            login(request, user)
            print(f"Login successful for user: {username}")  # 打印登录成功的信息
            # 保存用户信息到 session
            request.session['username'] = user.username
            request.session['user_id'] = user.id
            return Response({'code': 1, "message": "Login successful"}, status=status.HTTP_200_OK)
        
        print(f"Login failed for username: {username}")  # 打印登录失败的信息
        return Response({"error": "Invalid credentials"}, status=status.HTTP_401_UNAUTHORIZED)

# 在后续请求中访问session信息
class UserProfileAPIView(APIView):
    def get(self, request):
        username = request.session.get('username')
        print(f"Fetching profile for user: {username}")  # 打印正在获取用户信息的信息
        if username:
            # 获取其他需要的信息
            print(f"User profile fetched successfully for: {username}")  # 打印成功获取用户信息的信息
            return Response({"username": username}, status=status.HTTP_200_OK)
        
        print("User not logged in")  # 打印用户未登录的信息
        return Response({"error": "User not logged in"}, status=status.HTTP_401_UNAUTHORIZED)

# 登出时清除用户信息
from django.contrib.auth import logout

class LogoutAPIView(APIView):
    def post(self, request):
        print(f"Logging out user: {request.session.get('username')}")  # 打印正在登出用户的信息
        logout(request)
        # 清除 session 信息
        request.session.flush()
        print("Logout successful")  # 打印登出成功的信息
        return Response({'code': 1, "message": "Logout successful"}, status=status.HTTP_200_OK)
    

from .models import DashboardData
from .serializers import DashboardDataSerializer

class DashboardDataView(APIView):
    def get(self, request):
        data = DashboardData.objects.first()  # 假设只有一条数据
        serializer = DashboardDataSerializer(data)
        return Response(serializer.data)
    


# yolov5模型
from .models import DetectionResult
from .yolov560.detect import run  # 调用检测模型的函数
from rest_framework.exceptions import NotFound, APIException
from rest_framework.parsers import MultiPartParser, FormParser
from django.core.files.storage import default_storage
import json # 导入json模块
import os
from django.conf import settings
import base64
# 设置日志配置
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class GetDatas(APIView):
    def get(self, request):
        try:
            res = self.startDetect()
            data = {"message": res}
            return Response(data, content_type='application/json')
        except FileNotFoundError as e:
            logger.error(f"File not found: {str(e)}")
            raise NotFound(detail=f"File not found: {str(e)}")
        except Exception as e:
            logger.error(f"Error during detection: {str(e)}")
            raise APIException(detail=f"Error during detection: {str(e)}")

    def startDetect(self):
        current_file_path = os.path.dirname(__file__)
        logger.info(f"Current file path: {current_file_path}")

        weights = os.path.join(current_file_path, "yolov5", "weight", "best.pt")
        logger.info(f"Model weights path: {weights}")

        image_path = os.path.join(current_file_path, "yolov5", "image", "01_missing_hole_01.jpg")
        logger.info(f"Image path: {image_path}")

        args_dict = {
            "weights": weights,
            "source": image_path,
            "view_img": False,
            "conf_thres": 0.8,  # confidence threshold
            "iou_thres": 0.45  # NMS IOU threshold
        }

        result_json = self.detect(**args_dict)
        result_dict = json.loads(result_json)

        result_image_path = self.get_result_image_path(result_dict)
        logger.info(f"Result image path: {result_image_path}")

        return self.encode_image_to_base64(result_image_path)

    def detect(self, **kwargs):
        return run(**kwargs)

    def get_result_image_path(self, result_dict):
        current_file_path = os.path.dirname(__file__)
        saved_image_relative_path = result_dict["saveImg"]
        logger.info(f"Saved image relative path: {saved_image_relative_path}")

        # 如果路径中包含多余的 'detection' 目录，则移除之
        detection_dir = 'detection'
        if detection_dir in saved_image_relative_path:
            saved_image_relative_path = saved_image_relative_path.replace(detection_dir, '').strip(os.sep)

        result_image_path = os.path.join(current_file_path, saved_image_relative_path)
        logger.info(f"Final result image path: {result_image_path}")

        return result_image_path

    def encode_image_to_base64(self, image_path):
        if not os.path.exists(image_path):
            logger.error(f"File not found: {image_path}")
            raise FileNotFoundError(f"File not found: {image_path}")

        try:
            with open(image_path, "rb") as img_file:
                return base64.b64encode(img_file.read()).decode('utf-8')
        except FileNotFoundError as e:
            logger.error(f"Error reading file {image_path}: {str(e)}")
            raise e

class UploadFile(APIView):
    parser_classes = (MultiPartParser, FormParser)

    def post(self, request, *args, **kwargs):
        try:
            file_obj = request.FILES['file']
            model_name = request.data.get('model', 'best.pt')
            file_path = self.save_uploaded_file(file_obj)

            model_path = os.path.join(os.path.dirname(__file__), 'yolov5', 'weight', model_name)

            res = self.startDetect(file_path, model_path)
            data = {
                "image": res["image"],
                "data": res["data"]
            }
            self.save_detection_result(file_obj.name, res["data"])
            return Response(data, content_type='application/json')
        except Exception as e:
            logger.error(f"Error during file upload: {str(e)}")
            return Response({"error": str(e)}, status=500)

    def save_uploaded_file(self, file_obj):
        # 保存上传的文件到 MEDIA_ROOT 目录下
        upload_dir = os.path.join(settings.MEDIA_ROOT, 'uploads')
        os.makedirs(upload_dir, exist_ok=True)
        file_path = os.path.join(upload_dir, file_obj.name)
        with default_storage.open(file_path, 'wb+') as destination:
            for chunk in file_obj.chunks():
                destination.write(chunk)
        return file_path

    def startDetect(self, image_path, model_path):
        current_file_path = os.path.dirname(__file__)
        weights = model_path
        args_dict = {
            "weights": weights,
            "source": image_path,
            "view_img": False,
            "conf_thres": 0.8,
            "iou_thres": 0.45
        }
        result_json = self.detect(**args_dict)
        result_dict = json.loads(result_json)
        result_image_path = self.get_result_image_path(result_dict)
        result_image_base64 = self.encode_image_to_base64(result_image_path)

        detection_data = result_dict.get("data", [])
        if not detection_data:
            labels = "正常"
            confidences = "正常"
        else:
            labels = " ".join([d["label"] for d in detection_data])
            confidences = " ".join([str(d["confidence"]) for d in detection_data])

        return {
            "image": result_image_base64,
            "data": {
                "labels": labels,
                "confidences": confidences
            }
        }

    def detect(self, **kwargs):
        return run(**kwargs)

    def get_result_image_path(self, result_dict):
        current_file_path = os.path.dirname(__file__)
        saved_image_relative_path = result_dict["saveImg"]

        # 如果路径中包含多余的 'detection' 目录，则移除之
        detection_dir = 'detection'
        if detection_dir in saved_image_relative_path:
            saved_image_relative_path = saved_image_relative_path.replace(detection_dir, '').strip(os.sep)

        result_image_path = os.path.join(current_file_path, saved_image_relative_path)

        return result_image_path

    def encode_image_to_base64(self, image_path):
        if not os.path.exists(image_path):
            logger.error(f"File not found: {image_path}")
            raise FileNotFoundError(f"File not found: {image_path}")

        try:
            with open(image_path, "rb") as img_file:
                return base64.b64encode(img_file.read()).decode('utf-8')
        except FileNotFoundError as e:
            logger.error(f"Error reading file {image_path}: {str(e)}")
            raise e

    def save_detection_result(self, file_name, data):
        existing_result = DetectionResult.objects.filter(image_name=file_name).first()
        if existing_result:
            existing_result.labels = data['labels']
            existing_result.confidences = data['confidences']
            existing_result.save()
        else:
            labels = data['labels']
            confidences = data['confidences']
            result = DetectionResult(image_name=file_name, labels=labels, confidences=confidences)
            result.save()

